package com.example.wenmini.service.QsFill;

import com.example.wenmini.entity.QuestionnaireFillRequest;
import lombok.extern.slf4j.Slf4j;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;

@Service
@Slf4j
public class QuestionChoice {
    private static final Random random = new Random();
    private static final int WAIT_TIMEOUT = 10;


    // 单选题
    public void handleSingleChoice(WebElement question, QuestionnaireFillRequest.QuestionConfigDto config, Long taskId) {
        List<WebElement> options = question.findElements(By.cssSelector(".ui-radio"));
        if (options.isEmpty() || config.getOptions() == null || config.getOptions().isEmpty()) {
            return;
        }

        int selectedIndex = getRandomIndexByPercentage(config.getOptions());
        if (selectedIndex >= 0 && selectedIndex < options.size()) {
            options.get(selectedIndex).click();
            log.info("单选题选择了第{}个选项", selectedIndex + 1);
        }
    }

    // 多选题
    public void handleMultipleChoice(WebElement question, QuestionnaireFillRequest.QuestionConfigDto config, Long taskId) {
        List<WebElement> options = question.findElements(By.cssSelector(".ui-checkbox"));
        if (options.isEmpty() || config.getOptions() == null || config.getOptions().isEmpty()) {
            return;
        }

        // 获取配置中是否包含需要文本输入的选项
        boolean hasTextInput = config.isHasTextInput();

        List<Integer> selectedIndexes = getRandomIndexesByPercentage(config.getOptions());
        for (Integer index : selectedIndexes) {
            if (index >= 0 && index < options.size()) {
                long startTime = System.currentTimeMillis();
                WebElement option = options.get(index);
                option.click();
                log.info("多选题选择了第{}个选项", index + 1);
                
                // 只有当配置指定该选项需要文本输入时才处理
                QuestionnaireFillRequest.OptionConfigDto optionConfig = config.getOptions().get(index);
                if (hasTextInput && optionConfig.isHasTextInput()) {
                    try {
                        // 查找文本输入框
                        WebElement textInput = findTextInput(option);
                        
                        if (textInput != null && textInput.isDisplayed()) {
                            // 从配置的文本答案中随机选择一个
                            String textAnswer = getRandomTextAnswer(optionConfig.getTextAnswers());
                            
                            // 输入文本
                            textInput.clear();
                            textInput.sendKeys(textAnswer);
                            
                            log.info("多选题选项{}填写文本：{}", index + 1, textAnswer);
                        }
                    } catch (Exception e) {
                        log.error("处理选项{}的文本输入时出现异常：{}", index + 1, e.getMessage());
                    }
                }
                
                log.debug("处理选项{}总耗时：{}ms", index + 1, System.currentTimeMillis() - startTime);
            }
        }
    }

    private WebElement findTextInput(WebElement option) {
        // 首先检查直接相邻的输入框
        List<WebElement> siblingInputs = option.findElements(
            By.xpath("./following-sibling::input[@type='text'][1] | ./following-sibling::textarea[1]")
        );
        
        if (!siblingInputs.isEmpty() && siblingInputs.get(0).isDisplayed()) {
            return siblingInputs.get(0);
        }
        
        // 如果没找到相邻的，检查选项内部
        List<WebElement> innerInputs = option.findElements(
            By.xpath(".//input[@type='text'][1] | .//textarea[1]")
        );
        
        if (!innerInputs.isEmpty() && innerInputs.get(0).isDisplayed()) {
            return innerInputs.get(0);
        }
        
        return null;
    }

    private String getRandomTextAnswer(List<String> textAnswers) {
        if (textAnswers == null || textAnswers.isEmpty()) {
            return "无";
        }
        return textAnswers.get(random.nextInt(textAnswers.size()));
    }

    // 填空题
    public void handleTextQuestion(WebDriver driver, WebElement question,
                                    QuestionnaireFillRequest.QuestionConfigDto config, Long taskId)
            throws InterruptedException {
        if (config.getTextAnswers() == null || config.getTextAnswers().isEmpty()) {
            return;
        }
    
        WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(WAIT_TIMEOUT));
        JavascriptExecutor js = (JavascriptExecutor) driver;
        WebElement inputElement = null;
    
        try {
            // 获取问题的父元素
            WebElement fieldElement = question.findElement(By.xpath("./ancestor::div[contains(@class, 'field')]"));
            log.info("找到问题父元素: {}", fieldElement.getAttribute("class"));
    
            // 按优先级查找输入元素
            List<By> selectors = List.of(
                // 1. 传统input元素
                By.cssSelector("input[type='text'][id^='q'], input[type='text'][name^='q']"),
                // 2. 可编辑span元素
                By.cssSelector("span[contenteditable='true']"),
                // 3. 通用文本输入
                By.cssSelector("input[type='text'], textarea, .fillblank"),
                // 4. 其他可编辑元素
                By.cssSelector("[contenteditable='true']")
            );
    
            // 遍历所有选择器
            for (By selector : selectors) {
                List<WebElement> elements = fieldElement.findElements(selector);
                for (WebElement element : elements) {
                    if (element.isDisplayed()) {
                        inputElement = element;
                        log.info("找到输入元素，类型={}, class={}, contenteditable={}",
                                element.getTagName(),
                                element.getAttribute("class"),
                                element.getAttribute("contenteditable"));
                        break;
                    }
                }
                if (inputElement != null) break;
            }
    
            if (inputElement == null) {
                log.error("未找到可用的输入元素");
                return;
            }
    
            // 滚动到元素位置
            js.executeScript("arguments[0].scrollIntoView({behavior: 'smooth', block: 'center'});", inputElement);
            Thread.sleep(500);
    
            // 确保元素可交互
            wait.until(ExpectedConditions.elementToBeClickable(inputElement));
    
            // 随机选择一个答案
            String answer = config.getTextAnswers().get(random.nextInt(config.getTextAnswers().size()));
    
            // 根据元素类型选择不同的输入方式
            if (inputElement.getTagName().equals("span") || "true".equals(inputElement.getAttribute("contenteditable"))) {
                // 对于可编辑元素，使用JavaScript设置内容
                js.executeScript("arguments[0].textContent = '';", inputElement); // 清空内容
                Thread.sleep(300);
                
                // 模拟人工输入
                for (char c : answer.toCharArray()) {
                    js.executeScript(
                        "var el = arguments[0];" +
                        "el.textContent += arguments[1];" +
                        "var evt = new Event('input', {bubbles: true});" +
                        "el.dispatchEvent(evt);",
                        inputElement, String.valueOf(c)
                    );
                    Thread.sleep(50 + random.nextInt(50));
                }
            } else {
                // 对于传统input元素
                inputElement.clear();
                Thread.sleep(300);
                
                // 模拟人工输入
                for (char c : answer.toCharArray()) {
                    inputElement.sendKeys(String.valueOf(c));
                    Thread.sleep(50 + random.nextInt(50));
                }
            }
    
            // 触发相关事件
            js.executeScript(
                "var el = arguments[0];" +
                "el.dispatchEvent(new Event('change', {bubbles: true}));" +
                "el.dispatchEvent(new Event('blur', {bubbles: true}));" +
                "if(typeof hideTip === 'function') { hideTip(el); }",
                inputElement
            );
            Thread.sleep(300);
    
            // 验证输入
            String actualValue = inputElement.getTagName().equals("span") ? 
                (String) js.executeScript("return arguments[0].textContent;", inputElement) :
                inputElement.getAttribute("value");
                
            if (!answer.equals(actualValue)) {
                log.error("文本输入验证失败，期望：{}，实际：{}", answer, actualValue);
                throw new RuntimeException("文本输入验证失败");
            }
    
        } catch (Exception e) {
            log.error("处理文本题失败：{}", e.getMessage());
            throw e;
        }
    }

    // 按照百分比随机选择一个选项
    private int getRandomIndexByPercentage(List<QuestionnaireFillRequest.OptionConfigDto> options) {
        int randomNum = ThreadLocalRandom.current().nextInt(0, 100);
        int accumulatedPercentage = 0;

        for (int i = 0; i < options.size(); i++) {
            accumulatedPercentage += options.get(i).getPercentage();
            if (randomNum < accumulatedPercentage) {
                return i;
            }
        }

        return options.size() - 1; // 如果没有匹配的，返回最后一个选项
    }

    // 按照百分比随机选择多个选项
    private List<Integer> getRandomIndexesByPercentage(List<QuestionnaireFillRequest.OptionConfigDto> options) {
        List<Integer> selectedIndexes = new ArrayList<>();

        for (int i = 0; i < options.size(); i++) {
            QuestionnaireFillRequest.OptionConfigDto option = options.get(i);
            if (ThreadLocalRandom.current().nextInt(0, 100) < option.getPercentage()) {
                selectedIndexes.add(i);
            }
        }

        // 如果没有选中任何选项，随机选择一个
        if (selectedIndexes.isEmpty() && !options.isEmpty()) {
            selectedIndexes.add(ThreadLocalRandom.current().nextInt(0, options.size() - 1));
        }

        return selectedIndexes;
    }

}